/*
 * Copyright (c) 2014. kupat Corporation. All rights reserved.
 *  see statement on http://www.kupat.cn.
 */
package com.kfgj.hkp.common.dataaccess.mybatis;

import com.kfgj.hkp.common.BaseEntity;
import com.kfgj.hkp.common.dataaccess.PageResult;
import com.kfgj.hkp.common.dataaccess.enums.DataAccessErrorMsg;
import com.kfgj.hkp.common.exception.IllegalArgsException;
import com.kfgj.hkp.common.logging.Logger;
import com.kfgj.hkp.common.logging.LoggerFactory;
import com.kfgj.hkp.common.utils.GenericsUtils;
import com.kfgj.hkp.common.utils.ValidateUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by liwensihan on 2014/11/7.
 *
 * @author liwensihan
 */
public class AbstractMyBatisDao<T extends BaseEntity, PK extends Serializable> extends SqlSessionDaoSupport implements IMyBatisBaseDao<T, PK> {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    protected String mapperNamespace;

    public AbstractMyBatisDao() {
        this.mapperNamespace = GenericsUtils.getSuperClassGenricType(getClass()).getName() + ".";
    }

    @Autowired(required = false)
    @Override
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        super.setSqlSessionFactory(sqlSessionFactory);
    }

    @Autowired(required = false)
    @Override
    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        super.setSqlSessionTemplate(sqlSessionTemplate);
    }

    @Override
    public int insert(T entity) {
        ValidateUtils.notNull(entity, DataAccessErrorMsg.InsertArgsEmpty);
        List<T> entities = new ArrayList<T>();
        entities.add(entity);
        return this.batchInsert(entities);
    }

    @Override
    public int batchInsert(List<T> entities) {
        ValidateUtils.notNull(entities, DataAccessErrorMsg.InsertArgsEmpty);
        if (entities.size() < 1) {
            return 0;
        }
        return getSqlSession().insert(this.mapperNamespace + StatementIdConstants.BATCH_INSERT, entities);

    }

    @Override
    public int update(T entity) {
        ValidateUtils.notNull(entity, DataAccessErrorMsg.UpdateArgsEmpty);
        List<T> entities = new ArrayList<T>();
        entities.add(entity);
        return this.batchUpdate(entities);
    }

    @Override
    public int batchUpdate(List<T> entities) {
        ValidateUtils.notNull(entities, DataAccessErrorMsg.UpdateArgsEmpty);
        if (entities.size() < 1) {
            return 0;
        }
        return getSqlSession().update(this.mapperNamespace + StatementIdConstants.BATCH_UPDATE, entities);
    }

    @Override
    public int updateByNativeSql(String sql) {
        return this.getSqlSession().update(this.mapperNamespace + StatementIdConstants.UPDATE_BY_NATIVE_SQL, sql);
    }

    @Override
    public List<T> selectByNativeSql(String sql) {
        return this.getSqlSession().selectList(this.mapperNamespace + StatementIdConstants.SELECT_BY_NATIVE_SQL, sql);
    }

    @Override
    public T selectOneByNativeSql(String sql) {
        return this.getSqlSession().selectOne(this.mapperNamespace + StatementIdConstants.SELECT_ONE_BY_NATIVE_SQL, sql);
    }

    @Override
    public int countByNativeSql(String sql) {
        return this.getSqlSession().selectOne(this.mapperNamespace + StatementIdConstants.COUNT_BY_NATIVE_SQL, sql);
    }

    /**
     * 通过属性名称及值查询指定的记录
     *
     * @param propertyName
     * @param value
     * @return
     */
    @Override
    public T selectUniqueByProp(String propertyName, Object value) {

        ValidateUtils.notNull(propertyName, DataAccessErrorMsg.SelectArgsEmpty);
        ValidateUtils.notNull(value, DataAccessErrorMsg.SelectArgsEmpty);

        Map<String, Object> param = new HashMap<String, Object>();
        param.put(propertyName, value);

        return this.selectUniqueByMap(param);
    }

    /**
     * 通过很多参数查询唯一记录
     *
     * @param param
     * @return
     */
    @Override
    public T selectUniqueByMap(Map<String, Object> param) {
        return getSqlSession().selectOne(this.mapperNamespace + StatementIdConstants.SELECT_UNIQUE_BY_PROP, param);
    }

    @Override
    public int deleteById(PK id) {
        ValidateUtils.notNull(id, DataAccessErrorMsg.DeleteArgsEmpty);
        List<PK> ids = new ArrayList<PK>();
        ids.add(id);
        return this.batchDeleteByIds(ids);
    }

    @Override
    public int batchDeleteByIds(List<PK> ids) {
        ValidateUtils.notNull(ids, DataAccessErrorMsg.DeleteArgsEmpty);
        if (ids.size() < 1) {
            return 0;
        }
        return getSqlSession().delete(this.mapperNamespace + StatementIdConstants.BATCH_DELETE_BY_IDS, ids);
    }

    @Override
    public T selectById(PK id) {
        ValidateUtils.notNull(id, DataAccessErrorMsg.SelectArgsEmpty);
        return this.selectUniqueByProp(getIdColumnName(), id);
    }

    /**
     * 通过selectByMapCount 查询统计数量
     *
     * @param param
     * @return
     */
    @Override
    public int countByMap(Map<String, Object> param) {

        if (null == param) {
            param = new HashMap<String, Object>();
        }
        return this.selectCount(StatementIdConstants.COUNT_BY_MAP, param);
    }

    /**
     * 通过独立的ID名称查询统计数量
     *
     * @param statement
     * @param param
     * @return
     */
    @Override
    public int selectCount(String statement, Map<String, Object> param) {

        if (null == param) {
            param = new HashMap<String, Object>();
        }

        return (Integer) getSqlSession().selectOne(this.mapperNamespace + statement, param);
    }

    /**
     * 通过selectByMap的id语句查询list数据
     *
     * @param queryParam
     * @return
     */
    @Override
    public List<T> selectByMap(Map<String, Object> queryParam) {

        return this.selectByStatement(StatementIdConstants.SELECT_BY_MAP,queryParam);
//        return this.selectByMap(queryParam, getIdColumnName(), getDefaultAsc());
    }

    /**
     * 通过selectByMap的id语句查询list数据
     *
     * @param queryParam
     * @param orderBy
     * @param isAsc
     * @return
     */
    @Override
    public List<T> selectByMap(Map<String, Object> queryParam, String orderBy, boolean isAsc) {

        return this.selectByStatement(StatementIdConstants.SELECT_BY_MAP, queryParam, orderBy, isAsc);
    }

    /**
     * @param queryParam
     * @param start
     * @param pageSize
     * @return
     */
    @Override
    public PageResult<T> selectByMap(Map<String, Object> queryParam, int start, int pageSize) {

        return this.selectByMap(queryParam, start, pageSize, getIdColumnName(), getDefaultAsc());
    }

    @Override
    public PageResult<T> selectByMap(Map<String, Object> queryParam, int start, int pageSize, String orderBy, boolean isAsc) {

        return this.selectByStatement(StatementIdConstants.SELECT_BY_MAP, queryParam, start, pageSize, orderBy, isAsc);

    }

    @Override
    public List<T> selectByStatement(String statement, Map<String, Object> queryParam) {
        return getSqlSession().selectList(this.mapperNamespace + statement, queryParam);
//        return this.selectByStatement(statement, queryParam, getIdColumnName(), true);
    }

    @Override
    public List<T> selectByStatement(String statement, Map<String, Object> queryParam, String orderBy, boolean isAsc) {
        Map<String, Object> param = getParam(queryParam, orderBy, isAsc);

        return getSqlSession().selectList(this.mapperNamespace + statement, param);
    }

    @Override
    public PageResult<T> selectByStatement(String statement, Map<String, Object> queryParam, int start, int pageSize) {
        return this.selectByStatement(statement, queryParam, start, pageSize, getIdColumnName(), getDefaultAsc());
    }


    @Override
    public PageResult<T> selectByStatement(String statement, Map<String, Object> queryParam, int start, int pageSize, String orderBy, boolean isAsc) {
        if (pageSize < 1) {
            throw new IllegalArgsException("分页pageSize参数必须大于等于1");
        }

        if (start < 0) {
            throw new IllegalArgsException("分页start参数必须大于等于0");
        }

        queryParam = this.filterMap(queryParam);

        int count = this.selectCount(statement + "Count", queryParam);
        if (count < 1) {
            return new PageResult<T>(start, count, pageSize, null);
        }
        Map<String, Object> param = getParam(queryParam, orderBy, isAsc);

        List<T> data = null;
        /**
         * 在传入的map中有self_page 的key就说明需要自己做分页
         * 就不会用框架的分页来做
         */
        if (param.containsKey("self_page")) {
            param.put("offset", start);
            param.put("limit", pageSize);
            data = getSqlSession().selectList(this.mapperNamespace + statement, param);
        } else {
            data = getSqlSession().selectList(this.mapperNamespace + statement, param, new RowBounds(start, pageSize));

        }
        return new PageResult<T>(start, count, pageSize, data);
    }

    protected Map<String, Object> getParam(Map<String, Object> queryParam, String orderBy, boolean isAsc) {
        Map<String, Object> param = queryParam;
        if (null == param) {
            param = new HashMap<String, Object>();
        }

        if (!StringUtils.isEmpty(orderBy)) {
            param.put("orderBy", orderBy);
        }

        if (isAsc) {
            param.put("order", "ASC");
        } else {
            param.put("order", "DESC");
        }

        return param;
    }

    @Override
    public List<T> selectAll() {

        return this.selectAll(this.getIdColumnName(), false);

    }

    @Override
    public List<T> selectAll(String orderBy, boolean isAsc) {

        return this.selectByMap(null, orderBy, isAsc);
    }

    /**
     * 默认表的主键字段名字叫ID
     *
     * @return
     */
    protected String getIdColumnName() {
        return "id";
    }

    protected Boolean getDefaultAsc() {
        return true;
    }

    /**
     * 把查询条件中LIST集合查询编程IN语句后面的值
     * 在mybatis映射文件中通过 ${_key}来获取值
     *
     * @param map
     * @return
     */
    protected Map<String, Object> filterMap(Map<String, Object> map) {
        Map<String, Object> temp = new HashMap<String, Object>();
        if (null != map) {
            for (String key : map.keySet()) {
                Object obj = map.get(key);

                temp.put(key, obj);

                if (obj instanceof List || obj instanceof ArrayList) {
                    String vls = "";
                    for (Object s : (ArrayList<Object>) obj) {
                        if (s != null) {
                            if (s instanceof String) {
                                String t = (String) s;
                                if (StringUtils.isNotEmpty(t)) {
                                    vls += "'" + t + "',";
                                }
                            } else {
                                vls += s + ",";
                            }
                        }
                    }
                    if (StringUtils.isNotEmpty(vls)) {
                        vls = vls.substring(0, vls.length() - 1);
                        temp.put("_" + key, vls);
                    }
                }
            }
        }
        return temp;
    }

}

